﻿using System;
using System.Collections.Generic;
using Framework.Common.Reflection.RunSharpEmit;
using System.Reflection.Emit;
using System.Collections.Concurrent;

namespace Framework.Common.Reflection
{
    public static class DynamicMethodCreate
    {
        /// <summary>
        /// string 类型转化字典 
        /// </summary>
        public static readonly Dictionary<Type, string> StringConvertMethodDict;
        /// <summary>
        /// object 类型转化字典
        /// </summary>
        public static readonly Dictionary<Type, string> ObjectConvertMethodDict;
        /// <summary>
        /// 静态构造函数
        /// </summary>
        static DynamicMethodCreate()
        {
            StringConvertMethodDict = new Dictionary<Type, string>
                               {
                                   {typeof (Boolean), "StrToBoolean"},
                                   {typeof (Char), "StrToChar"},
                                   {typeof (SByte), "StrToSByte"},
                                   {typeof (Byte), "StrToByte"},
                                   {typeof (Int16), "StrToInt16"},
                                   {typeof (UInt16), "StrToUInt16"},
                                   {typeof (Int32), "StrToInt32"},
                                   {typeof (UInt32), "StrToUInt32"},
                                   {typeof (Int64), "StrToInt64"},
                                   {typeof (UInt64), "StrToUInt64"},
                                   {typeof (Single), "StrToSingle"},
                                   {typeof (Double), "StrToDouble"},
                                   {typeof (Decimal), "StrToDecimal"},
                                   {typeof (DateTime), "StrToDateTime"},
                                   {typeof (String), "StrToString"},
                                   {typeof (bool?), "StrToBooleanNullable"},
                                   {typeof (char?), "StrToCharNullable"},
                                   {typeof (sbyte?), "StrToSByteNullable"},
                                   {typeof (byte?), "StrToByteNullable"},
                                   {typeof (short?), "StrToInt16Nullable"},
                                   {typeof (ushort?), "StrToUInt16Nullable"},
                                   {typeof (int?), "StrToInt32Nullable"},
                                   {typeof (uint?), "StrToUInt32Nullable"},
                                   {typeof (long?), "StrToInt64Nullable"},
                                   {typeof (ulong?), "StrToUInt64Nullable"},
                                   {typeof (float?), "StrToSingleNullable"},
                                   {typeof (double?), "StrToDoubleNullable"},
                                   {typeof (decimal?), "StrToDecimalNullable"},
                                   {typeof (DateTime?), "StrToDateTimeNullable"}
                               };

            ObjectConvertMethodDict = new Dictionary<Type, string>
                               {
                                   {typeof (Boolean), "ObjectToBoolean"},
                                   {typeof (Char), "ObjectToChar"},
                                   {typeof (SByte), "ObjectToSByte"},
                                   {typeof (Byte), "ObjectToByte"},
                                   {typeof (Int16), "ObjectToInt16"},
                                   {typeof (UInt16), "ObjectToUInt16"},
                                   {typeof (Int32), "ObjectToInt32"},
                                   {typeof (UInt32), "ObjectToUInt32"},
                                   {typeof (Int64), "ObjectToInt64"},
                                   {typeof (UInt64), "ObjectToUInt64"},
                                   {typeof (Single), "ObjectToSingle"},
                                   {typeof (Double), "ObjectToDouble"},
                                   {typeof (Decimal), "ObjectToDecimal"},
                                   {typeof (DateTime), "ObjectToDateTime"},
                                   {typeof (String), "ObjectToString"},
                                   {typeof (bool?), "ObjectToBooleanNullable"},
                                   {typeof (char?), "ObjectToCharNullable"},
                                   {typeof (sbyte?), "ObjectToSByteNullable"},
                                   {typeof (byte?), "ObjectToByteNullable"},
                                   {typeof (short?), "ObjectToInt16Nullable"},
                                   {typeof (ushort?), "ObjectToUInt16Nullable"},
                                   {typeof (int?), "ObjectToInt32Nullable"},
                                   {typeof (uint?), "ObjectToUInt32Nullable"},
                                   {typeof (long?), "ObjectToInt64Nullable"},
                                   {typeof (ulong?), "ObjectToUInt64Nullable"},
                                   {typeof (float?), "ObjectToSingleNullable"},
                                   {typeof (double?), "ObjectToDoubleNullable"},
                                   {typeof (decimal?), "ObjectToDecimalNullable"},
                                   {typeof (DateTime?), "ObjectToDateTimeNullable"}
                               };
        }

        static readonly Type OwnerType = typeof(DynamicMethodCreate);

        #region Test
        /// <summary>
        /// 
        /// </summary>
        /// <param name="action"></param>
        /// <param name="returnType"></param>
        /// <param name="paramTypes"></param>
        public static void Test(Action<CodeGen> action, Type returnType, params Type[] paramTypes)
        {
            AssemblyGen ag = new AssemblyGen(@"c:\test.exe");
            TypeGen tg = ag.Public.Class("Hello").Public.Static;
            {
                MethodGen mg = tg.Method(returnType, "Main");
                if (paramTypes != null && paramTypes.Length > 0)
                {
                    for (int i = 0; i < paramTypes.Length; i++)
                    {
                        mg = mg.Parameter(paramTypes[i], "p" + i);
                    }
                }
                CodeGen cg = mg;
                action(cg);
            }
            ag.Save();
        }

        #region test func

        public static void TestFunc<TResult>(Action<CodeGen> action)
        {
            AssemblyGen ag = new AssemblyGen(@"c:\test.exe");
            TypeGen tg = ag.Public.Class("Hello").Public.Static;
            {
                CodeGen cg = tg.Method(typeof(TResult), "Main");
                action(cg);
            }
            ag.Save();
        }

        public static void TestFunc<TParam0, TResult>(Action<CodeGen> action)
        {
            AssemblyGen ag = new AssemblyGen(@"c:\test.exe");
            TypeGen tg = ag.Public.Class("Hello").Public.Static;
            {
                CodeGen cg = tg.Method(typeof(TResult), "Main")
                      .Parameter(typeof(TParam0), "p0");
                action(cg);
            }
            ag.Save();
        }

        public static void TestFunc<TParam0, TParam1, TResult>(Action<CodeGen> action)
        {
            AssemblyGen ag = new AssemblyGen(@"c:\test.exe");
            TypeGen tg = ag.Public.Class("Hello").Public.Static;
            {
                CodeGen cg = tg.Method(typeof(TResult), "Main")
                     .Parameter(typeof(TParam0), "p0")
                     .Parameter(typeof(TParam1), "p1");
                action(cg);
            }
            ag.Save();
        }

        public static void TestFunc<TParam0, TParam1, TParam2, TResult>(Action<CodeGen> action)
        {
            AssemblyGen ag = new AssemblyGen(@"c:\test.exe");
            TypeGen tg = ag.Public.Class("Hello").Public.Static;
            {
                CodeGen cg = tg.Method(typeof(TResult), "Main")
                    .Parameter(typeof(TParam0), "p0")
                    .Parameter(typeof(TParam1), "p1")
                    .Parameter(typeof(TParam2), "p2");
                action(cg);
            }
            ag.Save();
        }

        public static void TestFunc<TParam0, TParam1, TParam2, TParam3, TResult>(Action<CodeGen> action)
        {
            AssemblyGen ag = new AssemblyGen(@"c:\test.exe");
            TypeGen tg = ag.Public.Class("Hello").Public.Static;
            {
                CodeGen cg = tg.Method(typeof(TResult), "Main")
                    .Parameter(typeof(TParam0), "p0")
                    .Parameter(typeof(TParam1), "p1")
                    .Parameter(typeof(TParam2), "p2")
                    .Parameter(typeof(TParam3), "p3");
                action(cg);
            }
            ag.Save();
        }
        #endregion

        #region test action
        public static void TestAction(Action<CodeGen> action)
        {
            AssemblyGen ag = new AssemblyGen(@"c:\test.exe");
            TypeGen tg = ag.Public.Class("Hello").Public.Static;
            {
                CodeGen cg = tg.Method(typeof(void), "Main");
                action(cg);
            }
            ag.Save();
        }

        public static void TestAction<TParam0>(Action<CodeGen> action)
        {
            AssemblyGen ag = new AssemblyGen(@"c:\test.exe");
            TypeGen tg = ag.Public.Class("Hello").Public.Static;
            {
                CodeGen cg = tg.Method(typeof(void), "Main")
                      .Parameter(typeof(TParam0), "p0");
                action(cg);
            }
            ag.Save();
        }

        public static void TestAction<TParam0, TParam1>(Action<CodeGen> action)
        {
            AssemblyGen ag = new AssemblyGen(@"c:\test.exe");
            TypeGen tg = ag.Public.Class("Hello").Public.Static;
            {
                CodeGen cg = tg.Method(typeof(void), "Main")
                     .Parameter(typeof(TParam0), "p0")
                     .Parameter(typeof(TParam1), "p1");
                action(cg);
            }
            ag.Save();
        }

        public static void TestAction<TParam0, TParam1, TParam2>(Action<CodeGen> action)
        {
            AssemblyGen ag = new AssemblyGen(@"c:\test.exe");
            TypeGen tg = ag.Public.Class("Hello").Public.Static;
            {
                CodeGen cg = tg.Method(typeof(void), "Main")
                    .Parameter(typeof(TParam0), "p0")
                    .Parameter(typeof(TParam1), "p1")
                    .Parameter(typeof(TParam2), "p2");
                action(cg);
            }
            ag.Save();
        }

        public static void TestAction<TParam0, TParam1, TParam2, TParam3>(Action<CodeGen> action)
        {
            AssemblyGen ag = new AssemblyGen(@"c:\test.exe");
            TypeGen tg = ag.Public.Class("Hello").Public.Static;
            {
                CodeGen cg = tg.Method(typeof(void), "Main")
                    .Parameter(typeof(TParam0), "p0")
                    .Parameter(typeof(TParam1), "p1")
                    .Parameter(typeof(TParam2), "p2")
                    .Parameter(typeof(TParam3), "p3");
                action(cg);
            }
            ag.Save();
        }
        #endregion

        #endregion

        #region create delegate

        /// <summary>
        /// 参数 默认p0，p1，p2
        /// </summary>
        /// <param name="action"> </param>
        /// <param name="returnType"></param>
        /// <param name="paramTypes"></param>
        /// <returns></returns>
        public static DynamicMethod Create(Action<CodeGen> action, Type returnType, params Type[] paramTypes)
        {
            DynamicMethodGen dmg = DynamicMethodGen
                .Static(OwnerType)
                .Method(returnType);

            if (paramTypes != null && paramTypes.Length > 0)
            {
                for (int i = 0; i < paramTypes.Length; i++)
                {
                    dmg = dmg.Parameter(paramTypes[i], "p" + i);
                }
            }
            CodeGen cg = dmg.GetCode();
            action(cg);
            return dmg.GetCompletedDynamicMethod(true);
        }
        #endregion

        #region create func
        /// <summary>
        /// 参数 默认p0，p1，p2
        /// </summary>
        /// <returns></returns>
        public static Func<TResult> CreateFunc<TResult>(Action<CodeGen> action)
        {
            Func<TResult> result;
            int cacheKey = action.GetHashCode();
            if (!Singleton<ConcurrentDictionary<int, Func<TResult>>>.Instance.TryGetValue(cacheKey, out result))
            {
                DynamicMethodGen dmg = DynamicMethodGen.Static(OwnerType).Method(typeof(TResult));
                CodeGen cg = dmg.GetCode();
                action(cg);
                DynamicMethod dm = dmg.GetCompletedDynamicMethod(true);
                result = (Func<TResult>)dm.CreateDelegate(typeof(Func<TResult>));
                Singleton<ConcurrentDictionary<int, Func<TResult>>>.Instance.TryAdd(cacheKey, result);
            }
            return result;

        }
        /// <summary>
        /// 参数 默认p0，p1，p2
        /// </summary>
        /// <returns></returns>
        public static Func<TParam0, TResult> CreateFunc<TParam0, TResult>(Action<CodeGen> action)
        {
            Func<TParam0, TResult> result;
            int cacheKey = action.GetHashCode();
            if (!Singleton<ConcurrentDictionary<int, Func<TParam0, TResult>>>.Instance.TryGetValue(cacheKey, out result))
            {
                DynamicMethodGen dmg = DynamicMethodGen.Static(OwnerType).Method(typeof(TResult)).Parameter(typeof(TParam0), "p0");
                CodeGen cg = dmg.GetCode();
                action(cg);
                DynamicMethod dm = dmg.GetCompletedDynamicMethod(true);
                result = (Func<TParam0, TResult>)dm.CreateDelegate(typeof(Func<TParam0, TResult>));
                Singleton<ConcurrentDictionary<int, Func<TParam0, TResult>>>.Instance.TryAdd(cacheKey, result);
            }
            return result;
        }

        public static Func<TParam0, TParam1, TResult> CreateFunc<TParam0, TParam1, TResult>(Action<CodeGen> action)
        {
            Func<TParam0, TParam1, TResult> result;
            int cacheKey = action.GetHashCode();
            if (!Singleton<ConcurrentDictionary<int, Func<TParam0, TParam1, TResult>>>.Instance.TryGetValue(cacheKey, out result))
            {
                DynamicMethodGen dmg = DynamicMethodGen.Static(OwnerType).Method(typeof(TResult)).Parameter(typeof(TParam0), "p0").Parameter(typeof(TParam1), "p1");
                CodeGen cg = dmg.GetCode();
                action(cg);
                DynamicMethod dm = dmg.GetCompletedDynamicMethod(true);
                result = (Func<TParam0, TParam1, TResult>)dm.CreateDelegate(typeof(Func<TParam0, TParam1, TResult>));
                Singleton<ConcurrentDictionary<int, Func<TParam0, TParam1, TResult>>>.Instance.TryAdd(cacheKey, result);
            }
            return result;
        }

        public static Func<TParam0, TParam1, TParam2, TResult> CreateFunc<TParam0, TParam1, TParam2, TResult>(Action<CodeGen> action)
        {
            Func<TParam0, TParam1, TParam2, TResult> result;
            int cacheKey = action.GetHashCode();
            if (!Singleton<ConcurrentDictionary<int, Func<TParam0, TParam1, TParam2, TResult>>>.Instance.TryGetValue(cacheKey, out result))
            {
                DynamicMethodGen dmg = DynamicMethodGen.Static(OwnerType).Method(typeof(TResult)).Parameter(typeof(TParam0), "p0").Parameter(typeof(TParam1), "p1").Parameter(typeof(TParam2), "p2");
                CodeGen cg = dmg.GetCode();
                action(cg);
                DynamicMethod dm = dmg.GetCompletedDynamicMethod(true);
                result = (Func<TParam0, TParam1, TParam2, TResult>)dm.CreateDelegate(typeof(Func<TParam0, TParam1, TParam2, TResult>));
                Singleton<ConcurrentDictionary<int, Func<TParam0, TParam1, TParam2, TResult>>>.Instance.TryAdd(cacheKey, result);
            }
            return result;
        }

        public static Func<TParam0, TParam1, TParam2, TParam3, TResult> CreateFunc<TParam0, TParam1, TParam2, TParam3, TResult>(Action<CodeGen> action)
        {
            Func<TParam0, TParam1, TParam2, TParam3, TResult> result;
            int cacheKey = action.GetHashCode();
            if (!Singleton<ConcurrentDictionary<int, Func<TParam0, TParam1, TParam2, TParam3, TResult>>>.Instance.TryGetValue(cacheKey, out result))
            {
                DynamicMethodGen dmg = DynamicMethodGen.Static(OwnerType).Method(typeof(TResult)).Parameter(typeof(TParam0), "p0").Parameter(typeof(TParam1), "p1").Parameter(typeof(TParam2), "p2").Parameter(typeof(TParam3), "p3");
                CodeGen cg = dmg.GetCode();
                action(cg);
                DynamicMethod dm = dmg.GetCompletedDynamicMethod(true);
                result = (Func<TParam0, TParam1, TParam2, TParam3, TResult>)dm.CreateDelegate(typeof(Func<TParam0, TParam1, TParam2, TParam3, TResult>));
                Singleton<ConcurrentDictionary<int, Func<TParam0, TParam1, TParam2, TParam3, TResult>>>.Instance.TryAdd(cacheKey, result);
            }
            return result;
        }
        #endregion

        #region create action
        /// <summary>
        /// 参数 默认p0，p1，p2
        /// </summary>
        /// <returns></returns>
        public static Action CreateAction(Action<CodeGen> action)
        {
            Action result;
            int cacheKey = action.GetHashCode();
            if (!Singleton<ConcurrentDictionary<int, Action>>.Instance.TryGetValue(cacheKey, out result))
            {
                DynamicMethodGen dmg = DynamicMethodGen.Static(OwnerType).Method(typeof(void));
                CodeGen cg = dmg.GetCode();
                action(cg);
                DynamicMethod dm = dmg.GetCompletedDynamicMethod(true);
                result = (Action)dm.CreateDelegate(typeof(Action));
                Singleton<ConcurrentDictionary<int, Action>>.Instance.TryAdd(cacheKey, result);
            }
            return result;
        }
        /// <summary>
        /// 参数 默认p0，p1，p2
        /// </summary>
        /// <returns></returns>
        public static Action<TParam0> CreateAction<TParam0>(Action<CodeGen> action)
        {
            Action<TParam0> result;
            int cacheKey = action.GetHashCode();
            if (!Singleton<ConcurrentDictionary<int, Action<TParam0>>>.Instance.TryGetValue(cacheKey, out result))
            {
                DynamicMethodGen dmg = DynamicMethodGen.Static(OwnerType).Method(typeof(void)).Parameter(typeof(TParam0), "p0");
                CodeGen cg = dmg.GetCode();
                action(cg);
                DynamicMethod dm = dmg.GetCompletedDynamicMethod(true);
                result = (Action<TParam0>)dm.CreateDelegate(typeof(Action<TParam0>));
                Singleton<ConcurrentDictionary<int, Action<TParam0>>>.Instance.TryAdd(cacheKey, result);
            }
            return result;
        }

        public static Action<TParam0, TParam1> CreateAction<TParam0, TParam1>(Action<CodeGen> action)
        {
            Action<TParam0, TParam1> result;
            int cacheKey = action.GetHashCode();
            if (!Singleton<ConcurrentDictionary<int, Action<TParam0, TParam1>>>.Instance.TryGetValue(cacheKey, out result))
            {
                DynamicMethodGen dmg = DynamicMethodGen.Static(OwnerType).Method(typeof(void)).Parameter(typeof(TParam0), "p0").Parameter(typeof(TParam1), "p1");
                CodeGen cg = dmg.GetCode();
                action(cg);
                DynamicMethod dm = dmg.GetCompletedDynamicMethod(true);
                result = (Action<TParam0, TParam1>)dm.CreateDelegate(typeof(Action<TParam0, TParam1>));
                Singleton<ConcurrentDictionary<int, Action<TParam0, TParam1>>>.Instance.TryAdd(cacheKey, result);
            }
            return result;
        }

        public static Action<TParam0, TParam1, TParam2> CreateAction<TParam0, TParam1, TParam2>(Action<CodeGen> action)
        {
            Action<TParam0, TParam1, TParam2> result;
            int cacheKey = action.GetHashCode();
            if (!Singleton<ConcurrentDictionary<int, Action<TParam0, TParam1, TParam2>>>.Instance.TryGetValue(cacheKey, out result))
            {
                DynamicMethodGen dmg = DynamicMethodGen.Static(OwnerType).Method(typeof(void)).Parameter(typeof(TParam0), "p0").Parameter(typeof(TParam1), "p1").Parameter(typeof(TParam2), "p2");
                CodeGen cg = dmg.GetCode();
                action(cg);
                DynamicMethod dm = dmg.GetCompletedDynamicMethod(true);
                result = (Action<TParam0, TParam1, TParam2>)dm.CreateDelegate(typeof(Action<TParam0, TParam1, TParam2>));
                Singleton<ConcurrentDictionary<int, Action<TParam0, TParam1, TParam2>>>.Instance.TryAdd(cacheKey, result);
            }
            return result;
        }

        public static Action<TParam0, TParam1, TParam2, TParam3> CreateAction<TParam0, TParam1, TParam2, TParam3>(Action<CodeGen> action)
        {
            Action<TParam0, TParam1, TParam2, TParam3> result;
            int cacheKey = action.GetHashCode();
            if (!Singleton<ConcurrentDictionary<int, Action<TParam0, TParam1, TParam2, TParam3>>>.Instance.TryGetValue(cacheKey, out result))
            {
                DynamicMethodGen dmg = DynamicMethodGen.Static(OwnerType).Method(typeof(void)).Parameter(typeof(TParam0), "p0").Parameter(typeof(TParam1), "p1").Parameter(typeof(TParam2), "p2").Parameter(typeof(TParam3), "p3");
                CodeGen cg = dmg.GetCode();
                action(cg);
                DynamicMethod dm = dmg.GetCompletedDynamicMethod(true);
                result = (Action<TParam0, TParam1, TParam2, TParam3>)dm.CreateDelegate(typeof(Action<TParam0, TParam1, TParam2, TParam3>));
                Singleton<ConcurrentDictionary<int, Action<TParam0, TParam1, TParam2, TParam3>>>.Instance.TryAdd(cacheKey, result);
            }
            return result;
        }
        #endregion












        #region create func with cache key

        /// <summary>
        /// 参数 默认p0，p1，p2
        /// </summary>
        /// <returns></returns>
        public static Func<TResult> CreateFunc<TResult>(Action<CodeGen> action, string cacheKey)
        {
            Func<TResult> result;
            if (!Singleton<ConcurrentDictionary<string, Func<TResult>>>.Instance.TryGetValue(cacheKey, out result))
            {
                DynamicMethodGen dmg = DynamicMethodGen.Static(OwnerType).Method(typeof(TResult));
                CodeGen cg = dmg.GetCode();
                action(cg);
                DynamicMethod dm = dmg.GetCompletedDynamicMethod(true);
                result = (Func<TResult>)dm.CreateDelegate(typeof(Func<TResult>));
                Singleton<ConcurrentDictionary<string, Func<TResult>>>.Instance.TryAdd(cacheKey, result);
            }
            return result;

        }
        /// <summary>
        /// 参数 默认p0，p1，p2
        /// </summary>
        /// <returns></returns>
        public static Func<TParam0, TResult> CreateFunc<TParam0, TResult>(Action<CodeGen> action, string cacheKey)
        {
            Func<TParam0, TResult> result;
            if (!Singleton<ConcurrentDictionary<string, Func<TParam0, TResult>>>.Instance.TryGetValue(cacheKey, out result))
            {
                DynamicMethodGen dmg = DynamicMethodGen.Static(OwnerType).Method(typeof(TResult)).Parameter(typeof(TParam0), "p0");
                CodeGen cg = dmg.GetCode();
                action(cg);
                DynamicMethod dm = dmg.GetCompletedDynamicMethod(true);
                result = (Func<TParam0, TResult>)dm.CreateDelegate(typeof(Func<TParam0, TResult>));
                Singleton<ConcurrentDictionary<string, Func<TParam0, TResult>>>.Instance.TryAdd(cacheKey, result);
            }
            return result;
        }

        public static Func<TParam0, TParam1, TResult> CreateFunc<TParam0, TParam1, TResult>(Action<CodeGen> action, string cacheKey)
        {
            Func<TParam0, TParam1, TResult> result;
            if (!Singleton<ConcurrentDictionary<string, Func<TParam0, TParam1, TResult>>>.Instance.TryGetValue(cacheKey, out result))
            {
                DynamicMethodGen dmg = DynamicMethodGen.Static(OwnerType).Method(typeof(TResult)).Parameter(typeof(TParam0), "p0").Parameter(typeof(TParam1), "p1");
                CodeGen cg = dmg.GetCode();
                action(cg);
                DynamicMethod dm = dmg.GetCompletedDynamicMethod(true);
                result = (Func<TParam0, TParam1, TResult>)dm.CreateDelegate(typeof(Func<TParam0, TParam1, TResult>));
                Singleton<ConcurrentDictionary<string, Func<TParam0, TParam1, TResult>>>.Instance.TryAdd(cacheKey, result);
            }
            return result;
        }
        /// <summary>
        /// Func<TParam0, TParam1, TParam2, TResult>
        /// </summary>
        /// <typeparam name="TParam0"></typeparam>
        /// <typeparam name="TParam1"></typeparam>
        /// <typeparam name="TParam2"></typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="action"></param>
        /// <param name="cacheKey"></param>
        /// <returns></returns>
        public static Func<TParam0, TParam1, TParam2, TResult> CreateFunc<TParam0, TParam1, TParam2, TResult>(Action<CodeGen> action, string cacheKey)
        {
            Func<TParam0, TParam1, TParam2, TResult> result;
            if (!Singleton<ConcurrentDictionary<string, Func<TParam0, TParam1, TParam2, TResult>>>.Instance.TryGetValue(cacheKey, out result))
            {
                DynamicMethodGen dmg = DynamicMethodGen.Static(OwnerType).Method(typeof(TResult)).Parameter(typeof(TParam0), "p0").Parameter(typeof(TParam1), "p1").Parameter(typeof(TParam2), "p2");
                CodeGen cg = dmg.GetCode();
                action(cg);
                DynamicMethod dm = dmg.GetCompletedDynamicMethod(true);
                result = (Func<TParam0, TParam1, TParam2, TResult>)dm.CreateDelegate(typeof(Func<TParam0, TParam1, TParam2, TResult>));
                Singleton<ConcurrentDictionary<string, Func<TParam0, TParam1, TParam2, TResult>>>.Instance.TryAdd(cacheKey, result);
            }
            return result;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TParam0"></typeparam>
        /// <typeparam name="TParam1"></typeparam>
        /// <typeparam name="TParam2"></typeparam>
        /// <typeparam name="TParam3"></typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="action"></param>
        /// <param name="cacheKey"></param>
        /// <returns></returns>
        public static Func<TParam0, TParam1, TParam2, TParam3, TResult> CreateFunc<TParam0, TParam1, TParam2, TParam3, TResult>(Action<CodeGen> action, string cacheKey)
        {
            Func<TParam0, TParam1, TParam2, TParam3, TResult> result;
            if (!Singleton<ConcurrentDictionary<string, Func<TParam0, TParam1, TParam2, TParam3, TResult>>>.Instance.TryGetValue(cacheKey, out result))
            {
                DynamicMethodGen dmg = DynamicMethodGen.Static(OwnerType).Method(typeof(TResult)).Parameter(typeof(TParam0), "p0").Parameter(typeof(TParam1), "p1").Parameter(typeof(TParam2), "p2").Parameter(typeof(TParam3), "p3");
                CodeGen cg = dmg.GetCode();
                action(cg);
                DynamicMethod dm = dmg.GetCompletedDynamicMethod(true);
                result = (Func<TParam0, TParam1, TParam2, TParam3, TResult>)dm.CreateDelegate(typeof(Func<TParam0, TParam1, TParam2, TParam3, TResult>));
                Singleton<ConcurrentDictionary<string, Func<TParam0, TParam1, TParam2, TParam3, TResult>>>.Instance.TryAdd(cacheKey, result);
            }
            return result;
        }
        #endregion


        #region create action with cache key
        /// <summary>
        /// 参数 默认p0，p1，p2
        /// </summary>
        /// <returns></returns>
        public static Action CreateAction(Action<CodeGen> action, string cacheKey)
        {
            Action result;
            if (!Singleton<ConcurrentDictionary<string, Action>>.Instance.TryGetValue(cacheKey, out result))
            {
                DynamicMethodGen dmg = DynamicMethodGen.Static(OwnerType).Method(typeof(void));
                CodeGen cg = dmg.GetCode();
                action(cg);
                DynamicMethod dm = dmg.GetCompletedDynamicMethod(true);
                result = (Action)dm.CreateDelegate(typeof(Action));
                Singleton<ConcurrentDictionary<string, Action>>.Instance.TryAdd(cacheKey, result);
            }
            return result;
        }
        /// <summary>
        /// 参数 默认p0，p1，p2
        /// </summary>
        /// <returns></returns>
        public static Action<TParam0> CreateAction<TParam0>(Action<CodeGen> action, string cacheKey)
        {
            Action<TParam0> result;
            if (!Singleton<ConcurrentDictionary<string, Action<TParam0>>>.Instance.TryGetValue(cacheKey, out result))
            {
                DynamicMethodGen dmg = DynamicMethodGen.Static(OwnerType).Method(typeof(void)).Parameter(typeof(TParam0), "p0");
                CodeGen cg = dmg.GetCode();
                action(cg);
                DynamicMethod dm = dmg.GetCompletedDynamicMethod(true);
                result = (Action<TParam0>)dm.CreateDelegate(typeof(Action<TParam0>));
                Singleton<ConcurrentDictionary<string, Action<TParam0>>>.Instance.TryAdd(cacheKey, result);
            }
            return result;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TParam0"></typeparam>
        /// <typeparam name="TParam1"></typeparam>
        /// <param name="action"></param>
        /// <param name="cacheKey"></param>
        /// <returns></returns>
        public static Action<TParam0, TParam1> CreateAction<TParam0, TParam1>(Action<CodeGen> action, string cacheKey)
        {
            Action<TParam0, TParam1> result;
            if (!Singleton<ConcurrentDictionary<string, Action<TParam0, TParam1>>>.Instance.TryGetValue(cacheKey, out result))
            {
                DynamicMethodGen dmg = DynamicMethodGen.Static(OwnerType).Method(typeof(void)).Parameter(typeof(TParam0), "p0").Parameter(typeof(TParam1), "p1");
                CodeGen cg = dmg.GetCode();
                action(cg);
                DynamicMethod dm = dmg.GetCompletedDynamicMethod(true);
                result = (Action<TParam0, TParam1>)dm.CreateDelegate(typeof(Action<TParam0, TParam1>));
                Singleton<ConcurrentDictionary<string, Action<TParam0, TParam1>>>.Instance.TryAdd(cacheKey, result);
            }
            return result;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TParam0"></typeparam>
        /// <typeparam name="TParam1"></typeparam>
        /// <typeparam name="TParam2"></typeparam>
        /// <param name="action"></param>
        /// <param name="cacheKey"></param>
        /// <returns></returns>
        public static Action<TParam0, TParam1, TParam2> CreateAction<TParam0, TParam1, TParam2>(Action<CodeGen> action, string cacheKey)
        {
            Action<TParam0, TParam1, TParam2> result;
            if (!Singleton<ConcurrentDictionary<string, Action<TParam0, TParam1, TParam2>>>.Instance.TryGetValue(cacheKey, out result))
            {
                DynamicMethodGen dmg = DynamicMethodGen.Static(OwnerType).Method(typeof(void)).Parameter(typeof(TParam0), "p0").Parameter(typeof(TParam1), "p1").Parameter(typeof(TParam2), "p2");
                CodeGen cg = dmg.GetCode();
                action(cg);
                DynamicMethod dm = dmg.GetCompletedDynamicMethod(true);
                result = (Action<TParam0, TParam1, TParam2>)dm.CreateDelegate(typeof(Action<TParam0, TParam1, TParam2>));
                Singleton<ConcurrentDictionary<string, Action<TParam0, TParam1, TParam2>>>.Instance.TryAdd(cacheKey, result);
            }
            return result;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TParam0"></typeparam>
        /// <typeparam name="TParam1"></typeparam>
        /// <typeparam name="TParam2"></typeparam>
        /// <typeparam name="TParam3"></typeparam>
        /// <param name="action"></param>
        /// <param name="cacheKey"></param>
        /// <returns></returns>
        public static Action<TParam0, TParam1, TParam2, TParam3> CreateAction<TParam0, TParam1, TParam2, TParam3>(Action<CodeGen> action, string cacheKey)
        {
            Action<TParam0, TParam1, TParam2, TParam3> result;
            if (!Singleton<ConcurrentDictionary<string, Action<TParam0, TParam1, TParam2, TParam3>>>.Instance.TryGetValue(cacheKey, out result))
            {
                DynamicMethodGen dmg = DynamicMethodGen.Static(OwnerType).Method(typeof(void)).Parameter(typeof(TParam0), "p0").Parameter(typeof(TParam1), "p1").Parameter(typeof(TParam2), "p2").Parameter(typeof(TParam3), "p3");
                CodeGen cg = dmg.GetCode();
                action(cg);
                DynamicMethod dm = dmg.GetCompletedDynamicMethod(true);
                result = (Action<TParam0, TParam1, TParam2, TParam3>)dm.CreateDelegate(typeof(Action<TParam0, TParam1, TParam2, TParam3>));
                Singleton<ConcurrentDictionary<string, Action<TParam0, TParam1, TParam2, TParam3>>>.Instance.TryAdd(cacheKey, result);
            }
            return result;
        }
        #endregion


        ///// <summary>
        ///// 获取缓存key
        ///// </summary>
        ///// <param name="types"></param>
        ///// <returns></returns>
        //private static int GetCacheKey(params Type[] types)
        //{
        //    int key = 0;
        //    int paramLength = types.Length;
        //    for (int i = 1; i <= paramLength; i++)
        //    {
        //        key += types[i - 1].GetHashCode() * i;
        //    }
        //    return key;
        //}
    }
}
